package com.lingjtx.common.thread.config;

import com.alibaba.fastjson2.JSON;
import com.lingjtx.common.thread.api.WebClientApi;
import com.lingjtx.common.thread.api.WebClientExecutor;
import com.lingjtx.common.thread.commom.ObjectPoolRefreshEven;
import com.lingjtx.common.thread.core.ThreadPoolManager;
import com.lingjtx.common.thread.pooling.*;
import jakarta.mail.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;

import java.net.http.HttpClient;
import java.util.Objects;

@Configuration
public class ObjectPoolTemplateConfig implements ApplicationContextAware,
        ApplicationListener<ObjectPoolRefreshEven> {

    private static final Logger log = LoggerFactory.getLogger(ObjectPoolTemplateConfig.class);

    private final ExecutorConfig executorConfig;
    private final ThreadPoolManager threadPoolManager;
    private final ObjectPoolRegistry objectPoolRegistry;

    private ApplicationContext applicationContext;

    public ThreadPoolManager getThreadPoolManager() {
        return threadPoolManager;
    }

    public ObjectPoolTemplateConfig(ExecutorConfig executorConfig, ThreadPoolManager threadPoolManager, ObjectPoolRegistry objectPoolRegistry) {
        this.executorConfig = executorConfig;
        this.threadPoolManager = threadPoolManager;
        this.objectPoolRegistry = objectPoolRegistry;
    }

    public ObjectPoolTemplate<Session> mailObjectPoolTemplate() {
        ObjectFactory<Session> mailConnectionFactory = new MailConnectionFactory();
        return buildTemplate("mail", mailConnectionFactory);
    }

    public ObjectPoolTemplate<HttpClient> httpObjectPoolTemplate() {
        ObjectFactory<HttpClient> httpConnectionFactory = new HttpClientFactory(threadPoolManager);
        return buildTemplate("http", httpConnectionFactory);
    }

    public ObjectPoolTemplate<WebClient> webClientObjectPoolTemplate() {
        ObjectFactory<WebClient> webClientConnectionFactory = new WebClientFactory();
        return buildTemplate("webClient", webClientConnectionFactory);
    }

    public WebClientApi webClientApi() {
        WebClientApi clientApi = new WebClientApi();
        WebClientExecutor executor = new WebClientExecutor(webClientObjectPoolTemplate());
        return clientApi.webClientExecutor(executor);
    }

    public ObjectPoolRegistry objectPoolRegistry() {
        return new ObjectPoolRegistry();
    }

    public <T> ObjectPoolTemplate<T> buildTemplate(String name, ObjectFactory<T> factory) {
        ObjectPoolTemplate<T> template = new ObjectPoolTemplate<>(name, factory, threadPoolManager);
        ExecutorConfig.ObjectPoolConfig config = executorConfig.getTemplates().get(name);
        setObjectPoolTemplate(template, config);
        objectPoolRegistry.register(name, template);
        return template;
    }

    private void setObjectPoolTemplate(ObjectPoolTemplate<?> template, ExecutorConfig.ObjectPoolConfig config) {
        if (Objects.nonNull(config)) {
            template.refreshConfig(config);
        }

        // 设置刷新后钩子
        template.setRefreshCallback(() -> {
            // 可以自定义池刷新后的行为，比如通知监控、打印日志等
            log.info("设置的对象池配置：{}", JSON.toJSONString(config));
        });
    }

    public void refreshObjectPool(String name, ExecutorConfig.ObjectPoolConfig config) {
        ObjectPoolTemplate<?> template = (ObjectPoolTemplate<?>) applicationContext.getBean(name + "ObjectPoolTemplate");
        setObjectPoolTemplate(template, config);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void onApplicationEvent(ObjectPoolRefreshEven event) {
        refreshObjectPool(event.getName(), event.getConfig());
        log.info("对象池 [{}] 参数已热更新", event.getName());
    }
}
